package org.springside.modules.utils;

import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.impl.DefaultHttpClientConnection;
import org.apache.http.message.BasicHttpEntityEnclosingRequest;
import org.apache.http.message.BasicHttpRequest;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.params.SyncBasicHttpParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpProcessor;
import org.apache.http.protocol.HttpRequestExecutor;
import org.apache.http.protocol.ImmutableHttpProcessor;
import org.apache.http.protocol.RequestConnControl;
import org.apache.http.protocol.RequestContent;
import org.apache.http.protocol.RequestExpectContinue;
import org.apache.http.protocol.RequestTargetHost;
import org.apache.http.protocol.RequestUserAgent;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;

public class HttpUtils {

	private Logger logger = Logger.getLogger(this.getClass());
	private String host = "127.0.0.1";
	private int port = 80;
	private int so_timeout = 60000;
	private int connection_timeout = 60000;
	private List<String> requsetHeaders;

	public HttpUtils(String host, int port, int so_timeout, int connection_timeout, List<String> requsetHeaders) {
		this.host = host;
		this.port = port;
		this.so_timeout = so_timeout;
		this.connection_timeout = connection_timeout;
		this.requsetHeaders = requsetHeaders;
	}

	public HttpUtils() {
	}

	public List doRequest(String requestMethod, String url, HttpEntity httpEntity) throws HttpException, IOException {
		List result = new ArrayList();
		HttpHost httpHost = new HttpHost(host, port);
		HttpParams params = new SyncBasicHttpParams();
		params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, so_timeout).setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, connection_timeout);
		HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
		HttpProtocolParams.setContentCharset(params, "UTF-8");
		HttpProtocolParams.setUserAgent(params, "trswbapi/1.1");
		HttpProtocolParams.setUseExpectContinue(params, true);

		HttpContext context = new BasicHttpContext(null);
		DefaultHttpClientConnection conn = new DefaultHttpClientConnection();
		context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
		context.setAttribute(ExecutionContext.HTTP_TARGET_HOST, httpHost);

		HttpProcessor httpproc = new ImmutableHttpProcessor(new HttpRequestInterceptor[] { new RequestContent(), new RequestTargetHost(), new RequestConnControl(), new RequestUserAgent(), new RequestExpectContinue() });
		HttpRequestExecutor httpexecutor = new HttpRequestExecutor();
		try {
			if (!conn.isOpen()) {
				Socket socket = new Socket(httpHost.getHostName(), httpHost.getPort());
				conn.bind(socket, params);
			}
			BasicHttpRequest request = null;
			if (requestMethod.toUpperCase().equalsIgnoreCase("GET")) {
				request = new BasicHttpRequest("GET", url);
			} else {
				request = new BasicHttpEntityEnclosingRequest("POST", url);
				// StringEntity entity = new StringEntity(requestParam);
				// entity.setContentType("application/x-www-form-urlencoded");
				((BasicHttpEntityEnclosingRequest) request).setEntity(httpEntity);
			}
			if (requsetHeaders != null) {
				for (String kv : requsetHeaders) {
					String[] _kvs = kv.split(":");
					if (_kvs != null && _kvs.length == 2) {
						request.setHeader(_kvs[0], _kvs[1]);
					}
				}
			}

			logger.info(">> Request URI: " + request.getRequestLine().getUri());

			request.setParams(params);

			httpexecutor.preProcess(request, httpproc, context);
			HttpResponse response = httpexecutor.execute(request, conn, context);
			response.setParams(params);
			httpexecutor.postProcess(response, httpproc, context);

			String content = EntityUtils.toString(response.getEntity());
			Header[] headers = response.getAllHeaders();
			result.add(headers);
			result.add(content);
			logger.debug("<< Response: " + response.getStatusLine() + "\n" + content);
			return result;
		} finally {
			try {
				if (conn != null) {
					conn.close();
				}
			} catch (IOException e) {
				logger.error("", e);
			}
		}
	}

	/**
	 * 
	 * @param headers
	 * @return
	 */
	public static String getCookie(Header[] headers) {
		// Set-Cookie LT=1345534378; path=/; domain=login.sina.com.cn
		// Set-Cookie tgc=TGT-MjU1OTA2NTQ5Mw==-1345534378-xd-E3030DBE84D37C1A7AC0EDFF578B2AD9; domain=login.sina.com.cn; path=/; Httponly
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < headers.length; i++) {
			if (!headers[i].getName().toUpperCase().contains("COOKIE")) {
				continue;
			}
			String[] cookie = headers[i].getValue().split(";");
			for (String _cookie : cookie) {
				String[] _cookies = _cookie.split("=", 2);
				if (_cookies[0].trim().toUpperCase().equalsIgnoreCase("path") || _cookies[0].trim().toUpperCase().equalsIgnoreCase("domain") || _cookies[0].trim().toUpperCase().equalsIgnoreCase("Httponly")) {
					continue;
				}
				sb.append(_cookies[0]).append("=").append(_cookies[1]).append(";");
			}

		}
		return sb.toString();
	}

	public Logger getLogger() {
		return logger;
	}

	public void setLogger(Logger logger) {
		this.logger = logger;
	}

	public String getHost() {
		return host;
	}

	public void setHost(String host) {
		this.host = host;
	}

	public int getPort() {
		return port;
	}

	public void setPort(int port) {
		this.port = port;
	}

	public int getSo_timeout() {
		return so_timeout;
	}

	public void setSo_timeout(int so_timeout) {
		this.so_timeout = so_timeout;
	}

	public int getConnection_timeout() {
		return connection_timeout;
	}

	public void setConnection_timeout(int connection_timeout) {
		this.connection_timeout = connection_timeout;
	}

	public List<String> getRequsetHeaders() {
		return requsetHeaders;
	}

	public void setRequsetHeaders(List<String> requsetHeaders) {
		this.requsetHeaders = requsetHeaders;
	}

}
